package org.ephone;

import java.util.Vector;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.provider.BaseColumns;
import android.provider.Contacts.People;
import android.provider.Contacts.PeopleColumns;
import android.provider.Contacts.PhonesColumns;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.view.*;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;


public class DeepContactsActivity extends Activity implements OnClickListener, DialogInterface.OnClickListener {
	
	public Toast test;
	
	// Command listening and key generation
	public Handler handler;
	KeyGenerator keyThread;
	
	// Preferred contacts
	public static final String PREFS_CONTACTS = "preferredContacts";
	
	// Activity origin
	int preferredIndex;
	
	// Menu
	private AlertDialog.Builder dialogListMenu;
	AlertDialog dialogMenu;
	int menuItemSelected = 1;
	CharSequence[] menuItems;
	
	// Call members
    private Intent callIntent;
    //private PhoneStateListener mListener;
	
	// Query contacts members
	private Uri peopleUri = People.CONTENT_URI;
	private String contactsFields[] = new String [] { BaseColumns._ID, PeopleColumns.NAME, PhonesColumns.NUMBER };
	private String where;
	private Cursor contacts_cursor; // = getContentResolver().query(peopleUri, contactsFields, null, null, People.NAME + " ASC");
	
	// Logic members
	private String currCharSequence = ""; // Each new char press increments this
	private Vector <contactsRetrieved> currContacts;
	private Vector <Character> availableLetters; 
	private int slidingWindowContacts = 0;
	private int slidingWindowLetters = 0;
	private int countContacts = 0;
	private int countLetters = 0;
	
	// Graphical members
	private final Button contacts_list[] = new Button[5];
	private final Button letters_list[] = new Button[8];

	@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.contacts_deep);
        contacts_list[0] = (Button) findViewById(R.id.contacts_deep_button0);
        contacts_list[1] = (Button) findViewById(R.id.contacts_deep_button1);
        contacts_list[2] = (Button) findViewById(R.id.contacts_deep_button2);
        contacts_list[3] = (Button) findViewById(R.id.contacts_deep_button3);
        contacts_list[4] = (Button) findViewById(R.id.contacts_deep_button4);
        letters_list[0] = (Button) findViewById(R.id.contacts_deep_letter0);
        letters_list[1] = (Button) findViewById(R.id.contacts_deep_letter1);
        letters_list[2] = (Button) findViewById(R.id.contacts_deep_letter2);
        letters_list[3] = (Button) findViewById(R.id.contacts_deep_letter3);
        letters_list[4] = (Button) findViewById(R.id.contacts_deep_letter4);
        letters_list[5] = (Button) findViewById(R.id.contacts_deep_letter5);
        letters_list[6] = (Button) findViewById(R.id.contacts_deep_letter6);
        letters_list[7] = (Button) findViewById(R.id.contacts_deep_letter7);
        contacts_list[0].setOnClickListener(this);
        contacts_list[1].setOnClickListener(this);
        contacts_list[2].setOnClickListener(this);
        contacts_list[3].setOnClickListener(this);
        contacts_list[4].setOnClickListener(this);
        letters_list[0].setOnClickListener(this);
        letters_list[1].setOnClickListener(this);
        letters_list[2].setOnClickListener(this);
        letters_list[3].setOnClickListener(this);
        letters_list[4].setOnClickListener(this);
        letters_list[5].setOnClickListener(this);
        letters_list[6].setOnClickListener(this);
        letters_list[7].setOnClickListener(this);
        
        // MENU
        CharSequence[] tmp  = {getString(R.string.menu_back_option)};
        menuItems = tmp;
		dialogListMenu = new AlertDialog.Builder(this);
		dialogListMenu.setTitle("Choose an operation");
		dialogListMenu.setSingleChoiceItems(menuItems, 1, this);
		dialogMenu = dialogListMenu.create();
        
        // Preferred name
        preferredIndex = getIntent().getIntExtra("preferredIndex", -1);
        
        //DEBUG
        test = Toast.makeText(getApplicationContext(), "test Toast created", Toast.LENGTH_LONG);
        
        // Key commands
        handler = new Handler(Looper.getMainLooper());
	}
	
	@Override
	public void onStart() {
		super.onStart();
		try {
			onCharSeqChange();
		} catch (Exception ee) {
			test.setText(ee.toString());
			test.show();
		}
	}
	
	@Override
	public void onPause(){
		super.onPause();
		try {
			keyThread.exitActivity();
			keyThread = null;
			((ePhoneApp)getApplicationContext()).mListener = null;
		} catch (Exception ee) {
			test.setText(ee.toString());
			test.show();
		}
	}
	
	@Override
	public void onResume(){
		super.onResume();
		keyThread = new KeyGenerator(this, 1);
		keyThread.start();
		// CALLS
		((ePhoneApp)getApplicationContext()).mListener = new CallEndedListener(this, 1);
        ((ePhoneApp)getApplicationContext()).mTelMgr.listen(((ePhoneApp)getApplicationContext()).mListener, PhoneStateListener.LISTEN_CALL_STATE);
	}
	
	@Override
	public boolean onKeyDown (int keyCode, KeyEvent event) {

		Button up_contact = contacts_list[0];
		Button first_letter = letters_list[0];
		Button last_contact = contacts_list[4];
		int selected_contact_index = -1;
		int selected_letter_index = -1;
		
		for (int i = 0; i < contacts_list.length; i++){
			if (contacts_list[i].isFocused()){
				selected_contact_index = i;
				//contacts_list[i].setTextSize(0, 15);
			}
			if (contacts_list[i].getVisibility() == View.VISIBLE){
				last_contact = contacts_list[i];
			}
		}
		
		if (selected_contact_index == -1) {
			for (int i = 0; i < letters_list.length; i++){
				if (letters_list[i].isFocused()){
					selected_letter_index = i;
				}
			}
		}
		
		switch (keyCode) {
			case KeyEvent.KEYCODE_DPAD_DOWN:
				if (dialogMenu.isShowing()) {
					if (menuItemSelected < menuItems.length-1)
						menuItemSelected++;
					else
						menuItemSelected = 0;
					
					dialogMenu.hide();
					dialogListMenu.setSingleChoiceItems(menuItems, menuItemSelected, this);
					dialogMenu = dialogListMenu.create();
					dialogMenu.show();
				} else {
					// We are not in the last window
					if (slidingWindowContacts < (countContacts / contacts_list.length)) {
						if (selected_contact_index < 4){
							contacts_list[selected_contact_index+1].requestFocus();
						} else if (last_contact.isFocused()){
							contacts_list[0].requestFocus();
							slidingWindowContacts++;
							onSlideWindowContacts();
						}
					} else if (last_contact.isFocused()){
						return true;
					} else if (selected_contact_index < (countContacts % contacts_list.length)){
						contacts_list[selected_contact_index+1].requestFocus();
					}
				}
				
				break;
				
			case KeyEvent.KEYCODE_DPAD_UP:
				if (dialogMenu.isShowing()) {
					if (menuItemSelected > 0)
						menuItemSelected--;
					else
						menuItemSelected = menuItems.length-1;
					
					dialogMenu.hide();
					dialogListMenu.setSingleChoiceItems(menuItems, menuItemSelected, this);
					dialogMenu = dialogListMenu.create();
					dialogMenu.show();
				} else {
					if (selected_contact_index > 0){
						contacts_list[selected_contact_index-1].requestFocus();
					} else if (up_contact.isFocused() && slidingWindowContacts > 0){
						slidingWindowContacts--;
						onSlideWindowContacts();
						for (int i = 0; i < contacts_list.length; i++)
							contacts_list[i].setVisibility(View.VISIBLE);
						contacts_list[4].requestFocus();
					} else {
						contacts_list[0].requestFocus();
					}
				}
				break;
				
			case KeyEvent.KEYCODE_DPAD_LEFT:
				if (dialogMenu.isShowing()) {
					if (menuItemSelected > 0)
						menuItemSelected--;
					else
						menuItemSelected = menuItems.length-1;
					
					dialogMenu.hide();
					dialogListMenu.setSingleChoiceItems(menuItems, menuItemSelected, this);
					dialogMenu = dialogListMenu.create();
					dialogMenu.show();
				} else {
					if (selected_letter_index == -1) {
						first_letter.requestFocus();
					} else if (selected_letter_index > 0){
						letters_list[selected_letter_index-1].requestFocus();
					} else if (selected_letter_index == 0 || letters_list[0].isFocused()){
						if (slidingWindowLetters > 0){
							slidingWindowLetters--;
							onSlideWindowLetters();
							letters_list[7].requestFocus();
						}
					}
					
					/* else {
						for (int i = 0; i < contacts_list.length; i++)
							if (contacts_list[i].isFocused()){
								first_letter.requestFocus();
								break;
							}
					} */
				}
				break;
				
			case KeyEvent.KEYCODE_DPAD_RIGHT:
				if (dialogMenu.isShowing()) {
					if (menuItemSelected < menuItems.length-1)
						menuItemSelected++;
					else
						menuItemSelected = 0;
					
					dialogMenu.hide();
					dialogListMenu.setSingleChoiceItems(menuItems, menuItemSelected, this);
					dialogMenu = dialogListMenu.create();
					dialogMenu.show();
				} 
				else {
					int indexLastLetter = 0;
					// Get the last visible letter
					for (int i = 0; i < letters_list.length; i++){
						if (letters_list[i].getVisibility() == View.INVISIBLE)
							break;
						indexLastLetter = i;
					}
					
					if (selected_letter_index == -1) { // If one of the contacts is displayed
						letters_list[indexLastLetter].requestFocus();
					} else {
						if (selected_letter_index < indexLastLetter){
							letters_list[selected_letter_index+1].requestFocus();
						}
						// If the last visible letter, on the right, is focused
						else if (selected_letter_index == indexLastLetter || letters_list[indexLastLetter].isFocused()){
							// If in the last window
							slidingWindowLetters = (slidingWindowLetters < (countLetters / letters_list.length)) ? (slidingWindowLetters + 1) : 0;					
							letters_list[0].requestFocus();
							onSlideWindowLetters();					
						}
					}
				}
				break;
				
			case KeyEvent.KEYCODE_MENU:
				if (currCharSequence == null || currCharSequence.contentEquals("")) {
					CharSequence[] tmp = {getString(R.string.menu_back_option)};
					menuItems = tmp;
				} else
				{
					CharSequence[] tmp = {getString(R.string.menu_back_option), getString(R.string.menu_del_letter_option), getString(R.string.menu_del_letters_option)};
					menuItems = tmp;
				}
				
				//dialogListMenu = new AlertDialog.Builder(this);
				//dialogListMenu.setTitle("Choose an operation");
				dialogListMenu.setSingleChoiceItems(menuItems, 1, this);
				dialogMenu = dialogListMenu.create();
				dialogMenu.show();
				break;
				
			case KeyEvent.KEYCODE_DPAD_CENTER:
				if (dialogMenu.isShowing()) {
					this.onClick(dialogMenu, menuItemSelected);
				} else
					this.onClick(this.getCurrentFocus());
				break;
			
			case KeyEvent.KEYCODE_BACK:
				finish();
				break;
		}
		super.onKeyDown(keyCode, event);
		return true;
	}

	// MENU DIALOG HANDLER
	public void onClick(DialogInterface dialog, int item) {		
		boolean callOnCharSeqChange = false;
        switch (item){
        	case 0:
        		finish();
        		break;
        
			case 1:
				try {
					currCharSequence = currCharSequence.substring(0, currCharSequence.length()-1);
				} catch (Exception ee){ currCharSequence = ""; 	}
				callOnCharSeqChange = true;
				break;
				
			case 2:
				currCharSequence = "";
				callOnCharSeqChange = true;	
				break;
        }
        //dialog.dismiss();
        dialogMenu.hide();
		dialogMenu = dialogListMenu.create();
        if (callOnCharSeqChange)
        	onCharSeqChange();
    }
	

	/*
	 * onClick(View v)
	 * 	- If a letter is clicked, re-compute the contacts
	 * 	- Else if it is a contact button, call it
	 */
	public void onClick(View v) {
		switch (v.getId()){
			// Letters
			case R.id.contacts_deep_letter0:
				try {
					currCharSequence += (String)letters_list[0].getText();
					onCharSeqChange();
				} catch (Exception ee) {
					currCharSequence = "";
					onCharSeqChange();
				}
				break;
			case R.id.contacts_deep_letter1:
				currCharSequence += (String)letters_list[1].getText();
				onCharSeqChange();
				break;
			case R.id.contacts_deep_letter2:
				currCharSequence += (String)letters_list[2].getText();
				onCharSeqChange();
				break;
			case R.id.contacts_deep_letter3:
				currCharSequence += (String)letters_list[3].getText();
				onCharSeqChange();
				break;
			case R.id.contacts_deep_letter4:
				currCharSequence += (String)letters_list[4].getText();
				onCharSeqChange();
				break;
			case R.id.contacts_deep_letter5:
				currCharSequence += (String)letters_list[5].getText();
				onCharSeqChange();
				break;
			case R.id.contacts_deep_letter6:
				currCharSequence += (String)letters_list[6].getText();
				onCharSeqChange();
				break;
			case R.id.contacts_deep_letter7:
				currCharSequence += (String)letters_list[7].getText();
				onCharSeqChange();
				break;
			
			// Names
			case R.id.contacts_deep_button0:
				clickContact(0);
                break;
			case R.id.contacts_deep_button1:
				clickContact(1);
                break;
			case R.id.contacts_deep_button2:
				clickContact(2);
                break;
			case R.id.contacts_deep_button3:
				clickContact(3);
                break;
			case R.id.contacts_deep_button4:
				clickContact(4);
                break;
            
		}
		
	}
	
	private void clickContact(int buttonIndex){
		
		switch(preferredIndex){
			case -1:
				try{
	                callIntent = new Intent(Intent.ACTION_CALL, Uri
	                        .parse("tel:"+currContacts.elementAt(slidingWindowContacts * contacts_list.length + buttonIndex).phone));
	                startActivity(callIntent);
				} catch (Exception ee){
					test.setText(ee.toString());
					test.show();
				}
				break;
			case 0:
			case 1:
			case 2:
				SharedPreferences settings = getSharedPreferences(PREFS_CONTACTS, 0);
				SharedPreferences.Editor editor = settings.edit();
				editor.putInt("id"+(new Integer(preferredIndex)).toString(), currContacts.elementAt(slidingWindowContacts * contacts_list.length + buttonIndex).id);
				editor.commit();
				finish();
				break;
		}
	}
	
	/*
	 * onCharSeqChange()
	 * Data retrieving core function, called each time 'currCharSequence' is updated
	 * 	- If 'currCharSequence' is not empty, toast it
	 * 	- Query the Content DB about names starting with 'currCharSequence'
	 * 	- Update 'availableLetters' and 'currContacts'
	 * 	- Hide all the buttons: they will be displayed if necessary
	 * 	- call onSlideWindowLetters();
     * 	- call onSlideWindowContacts();
	 */
	synchronized private void onCharSeqChange() {
		
		if (!currCharSequence.contentEquals("")){
			Toast toast = Toast.makeText(getApplicationContext(), "'"+currCharSequence+"'", Toast.LENGTH_SHORT);
			toast.show();
			where = "NAME LIKE '" + currCharSequence + "%'";
		} else {
			where = null;
		}

		try {
			contacts_cursor = getContentResolver().query(peopleUri, contactsFields, where, null, PeopleColumns.NAME + " ASC");
		} catch(Exception ee){
			currCharSequence = "";
			contacts_cursor = getContentResolver().query(peopleUri, contactsFields, null, null, PeopleColumns.NAME + " ASC");
		}
		currContacts = new Vector<contactsRetrieved>();
		availableLetters = new Vector<Character>();
		
		if (contacts_cursor.moveToFirst()) {
    		int nameColumn = contacts_cursor.getColumnIndex(PeopleColumns.NAME);
    		int phoneColumn = contacts_cursor.getColumnIndex(PhonesColumns.NUMBER);
    		int idColumn = contacts_cursor.getColumnIndex(BaseColumns._ID);
    		
    		Character tmpLetter = new Character(' ');
    		countContacts = 0;
    		countLetters = 0;
    		slidingWindowContacts = 0;
    		slidingWindowLetters = 0;
    		do {
    			String _id = contacts_cursor.getString(idColumn);
    			String _name = contacts_cursor.getString(nameColumn);
    			String _phone = contacts_cursor.getString(phoneColumn);
    			
    			// Insert a new available letter: the char used is computed on the 'currCharSequence' length
    			if (_name.toUpperCase().charAt(currCharSequence.length()) != tmpLetter) {
    				tmpLetter = _name.toUpperCase().charAt(currCharSequence.length());
    				availableLetters.add(tmpLetter);
    				countLetters++;
    			}
    			
    			// Insert the contact
    			currContacts.add(new contactsRetrieved(countContacts, _id, _name, _phone));
    			if (countContacts < contacts_list.length){
    				contacts_list[countContacts].setText(currContacts.elementAt(countContacts).name + "\n" + currContacts.elementAt(countContacts).phone);
    			}
    			countContacts++;
    		} while (contacts_cursor.moveToNext());
    		
    		for (int i = 0; i < contacts_list.length; i++)
    			contacts_list[i].setVisibility(View.INVISIBLE);
    		
    		for (int i = 0; i < letters_list.length; i++)
    			letters_list[i].setVisibility(View.INVISIBLE);
    		
    		onSlideWindowLetters();
    		onSlideWindowContacts();
		}
		else {
			test.setText("no names");
			test.show();
		}
	}
	
	/*
	 * onSlideWindowContacts()
	 * For each contact button:
	 * 	- If the window displayed is a full one (not the last), or if it the last one but the button is a good one, update the button text and display it
	 * 	- Else (we are at the last window) if the button doesn't correspond to a real contact, hide it
	 */
	private void onSlideWindowContacts(){
		for (int i = 0; i < countContacts && i < contacts_list.length; i++){
			if ((slidingWindowContacts < (countContacts / contacts_list.length)) || i < (countContacts % contacts_list.length)){
				contacts_list[i].setText(currContacts.elementAt(slidingWindowContacts * contacts_list.length + i).name + "\n" + currContacts.elementAt(slidingWindowContacts * contacts_list.length + i).phone);
				contacts_list[i].setVisibility(View.VISIBLE);
			} else if (i >= (countContacts % contacts_list.length)){
				contacts_list[i].setVisibility(View.INVISIBLE);
			}
		}
	}
	
	private void onSlideWindowLetters(){
		for (int i = 0; i < countLetters && i < letters_list.length; i++) {
			if ((slidingWindowLetters < (countLetters / letters_list.length)) || (i < (countLetters % letters_list.length))){
				letters_list[i].setText(availableLetters.elementAt(slidingWindowLetters * letters_list.length + i).toString());
				letters_list[i].setVisibility(View.VISIBLE);
			} else if (i >= (countLetters % letters_list.length)){
				letters_list[i].setVisibility(View.INVISIBLE);
			} 
		}
	}
	
	public class contactsRetrieved {
		public int seq_num;
		public int id;
		public String name;
		public String phone;
		
		contactsRetrieved(int seq_num, String id, String name, String phone){
			this.seq_num = seq_num;
			this.id = new Integer(id);
			this.name = name;
			this.phone = phone;
		}
	}
	
	public class CallEndedListener extends PhoneStateListener {
        boolean called = false;
        
        ePhoneApp appCommand;
        
        private Activity activityIstance;
        private int typeOfActivity = 1; // 0 for Contacts ; 1 for DeepContacts
        
        public CallEndedListener(Activity istance, int type){
        	activityIstance = istance;
        	typeOfActivity = type;
        	appCommand = (ePhoneApp)activityIstance.getApplicationContext();
        }

        @Override
        public void onCallStateChanged(int state, String incomingNumber) {
        	
            if (called && state == TelephonyManager.CALL_STATE_IDLE) {
                called = false;
                appCommand.mTelMgr.listen(this, PhoneStateListener.LISTEN_NONE);
                //mTelMgr.listen(mListener, PhoneStateListener.LISTEN_CALL_STATE);
                try {
                	/*
                	Intent t = new Intent();
                	if (typeOfActivity == 0)
                		t = new Intent(activityIstance, ContactsActivity.class);
                	else if (typeOfActivity == 1)
                		t = new Intent(activityIstance, DeepContactsActivity.class);
                	*/
                	Intent t = new Intent(activityIstance, DeepContactsActivity.class);
                    //t.setAction(Intent.ACTION_MAIN);
                    //t.addCategory(Intent.CATEGORY_LAUNCHER);
                    t.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                    //t.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(t);
                } catch (Exception e) {
                	if (typeOfActivity == 0){
                		((ContactsActivity)activityIstance).test.setText("ContactsActivity: " +e.toString());
                		((ContactsActivity)activityIstance).test.show();
                	}
                	else if (typeOfActivity == 1){
                		((DeepContactsActivity)activityIstance).test.setText("DeepContactsActivity: " +e.toString());
                		((DeepContactsActivity)activityIstance).test.show();
                	}
                }
            } else if(TelephonyManager.CALL_STATE_RINGING == state) {
                
            } else {
                if (state == TelephonyManager.CALL_STATE_OFFHOOK)
                    called = true;
            }
        }
    }
}
